package example

import (
	"errors"
	"fmt"
	"log"
	"mime/multipart"
	"strconv"
	"strings"

	"github.com/flipped-aurora/gin-vue-admin/server/global"
	"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
	"github.com/flipped-aurora/gin-vue-admin/server/model/example"
	"github.com/flipped-aurora/gin-vue-admin/server/utils/upload"
)

//@author: [piexlmax](https://github.com/piexlmax)
//@function: Upload
//@description: 创建文件上传记录
//@param: file model.ExaFileUploadAndDownload
//@return: error

func (e *FileUploadAndDownloadService) Upload(file example.ExaFileUploadAndDownload) error {
	return global.GVA_DB.Create(&file).Error
}

//@author: [piexlmax](https://github.com/piexlmax)
//@function: FindFile
//@description: 查询文件记录
//@param: id uint
//@return: model.ExaFileUploadAndDownload, error

func (e *FileUploadAndDownloadService) FindFile(id uint) (example.ExaFileUploadAndDownload, error) {
	var file example.ExaFileUploadAndDownload
	err := global.GVA_DB.Where("id = ?", id).First(&file).Error
	return file, err
}

//@author: [piexlmax](https://github.com/piexlmax)
//@function: DeleteFile
//@description: 删除文件记录
//@param: file model.ExaFileUploadAndDownload
//@return: err error

func (e *FileUploadAndDownloadService) DeleteFile(file example.ExaFileUploadAndDownload) (err error) {
	var fileFromDb example.ExaFileUploadAndDownload
	fileFromDb, err = e.FindFile(file.ID)
	if err != nil {
		return
	}
	// 文件系统删除
	oss := upload.NewOss()
	if err = oss.DeleteFile(fileFromDb.Key); err != nil {
		log.Println("文件删除失败", err)
	}
	// 数据库逻辑删除
	err = global.GVA_DB.Where("id = ?", file.ID).Unscoped().Delete(&file).Error
	return err
}

// DeleteDir 删除文件夹
func (e *FileUploadAndDownloadService) DeleteDir(file example.ExaFileUploadAndDownload, userName string) (err error) {
	log.Printf("DeleteDir 入参:%#v\n", file)
	var fileFromDb example.ExaFileUploadAndDownload
	name := file.LogicAddress
	if name != "/" {
		name += "/"
	}
	name += file.Name
	log.Printf("Name:%v", name)
	db := global.GVA_DB
	err = db.Where("id = ?", file.ID).First(&fileFromDb).Error
	if err != nil {
		return
	}
	if userName != "admin" {
		if fileFromDb.Creator != userName {
			return errors.New("文件夹用户不正确")
		}
	}
	// 数据库逻辑删除
	err = db.Where("id = ?", file.ID).Unscoped().Delete(&file).Error
	if err != nil {
		log.Println("文件夹删除失败", err)
	}
	condition := fmt.Sprintf("logic_address = '%s' OR logic_address LIKE '%s/%%'", name, name)
	log.Printf("condition:%v", condition)
	// Unscoped 硬删除
	err = db.Where(condition).Unscoped().Delete(&example.ExaFileUploadAndDownload{}).Error
	if err != nil {
		log.Println("文件夹及子文件夹内容删除失败", err)
	}
	return err
}

// EditFileName 编辑文件名
func (e *FileUploadAndDownloadService) EditFileName(file example.ExaFileUploadAndDownload) (err error) {
	var fileFromDb example.ExaFileUploadAndDownload
	return global.GVA_DB.Where("id = ?", file.ID).First(&fileFromDb).Update("name", file.Name).Error
}

// EditFileDesc 编辑备注
func (e *FileUploadAndDownloadService) EditFileDesc(file example.ExaFileUploadAndDownload) (err error) {
	var fileFromDb example.ExaFileUploadAndDownload
	return global.GVA_DB.Where("id = ?", file.ID).First(&fileFromDb).Update("desc", file.Desc).Error
}

//@author: [piexlmax](https://github.com/piexlmax)
//@function: GetFileRecordInfoList
//@description: 分页获取数据
//@param: info request.PageInfo
//@return: list interface{}, total int64, err error

func (e *FileUploadAndDownloadService) GetFileRecordInfoList(info request.PageInfo) (list interface{}, total int64, err error) {
	log.Printf("GetFileRecordInfoList 入参:%#v\n", info)
	limit := info.PageSize
	offset := info.PageSize * (info.Page - 1)
	keyword := info.Keyword

	db := global.GVA_DB.Model(&example.ExaFileUploadAndDownload{})
	var fileLists []example.ExaFileUploadAndDownload
	// 全局搜索
	if info.GlobalSearch {
		wildcardSuffix := "%"
		if info.Dir != "/" {
			wildcardSuffix = "/" + wildcardSuffix
		}
		// 全局搜索：查询当前文件夹及其所有子文件夹
		db = db.Where("logic_address = ? OR logic_address LIKE ?", info.Dir, info.Dir+wildcardSuffix)
	} else {
		db = db.Where("logic_address = ?", info.Dir)
	}
	// 管理员可以看到所有的
	if info.UserName != "admin" {
		db = db.Where("(tag = ?) OR (permission = ?) OR (permission = ? AND creator = ?)", "dir", true, false, info.UserName)
	}
	// 搜索逻辑
	if info.Tag != "" {
		if info.Tag == "txt" {
			db = db.Where("name LIKE ?", "%.txt")
		} else if info.Tag == "tp" {
			db = db.Where("(name LIKE ? OR name LIKE ? OR name LIKE ? OR name LIKE ? OR name LIKE ? OR name LIKE ?)",
				"%.bmp", "%.jpg", "%.png", "%.tif", "%.svg", "%.jpeg")
		} else if info.Tag == "xls" {
			db = db.Where("(name LIKE ? OR name LIKE ?)", "%.xls", "%.xlsx")
		} else if info.Tag == "wd" {
			db = db.Where("(name LIKE ? OR name LIKE ?)", "%.doc", "%.docx")
		} else if info.Tag == "ppt" {
			db = db.Where("(name LIKE ? OR name LIKE ?)", "%.ppt", "%.pptx")
		} else if info.Tag == "pdf" {
			db = db.Where("name LIKE ?", "%.pdf")
		} else if info.Tag == "zip" {
			db = db.Where("(name LIKE ? OR name LIKE ? OR name LIKE ?)", "%.rar", "%.zip", "%.7z")
		} else if info.Tag == "exe" {
			db = db.Where("name LIKE ?", "%.exe")
		} else if info.Tag == "else" {
			db = db.Where("name NOT LIKE ?", "%.txt")
			db = db.Where("name NOT LIKE ?", "%.bmp")
			db = db.Where("name NOT LIKE ?", "%.jpg")
			db = db.Where("name NOT LIKE ?", "%.png")
			db = db.Where("name NOT LIKE ?", "%.tif")
			db = db.Where("name NOT LIKE ?", "%.svg")
			db = db.Where("name NOT LIKE ?", "%.doc")
			db = db.Where("name NOT LIKE ?", "%.docx")
			db = db.Where("name NOT LIKE ?", "%.ppt")
			db = db.Where("name NOT LIKE ?", "%.pptx")
			db = db.Where("name NOT LIKE ?", "%.pdf")
			db = db.Where("name NOT LIKE ?", "%.rar")
			db = db.Where("name NOT LIKE ?", "%.zip")
			db = db.Where("name NOT LIKE ?", "%.7z")
			db = db.Where("name NOT LIKE ?", "%.exe")
			db = db.Where("name NOT LIKE ?", "%.xls")
			db = db.Where("name NOT LIKE ?", "%.xlsx")
		}
	}
	if info.Creator != "" {
		db = db.Where("creator LIKE ?", "%"+info.Creator+"%")
	}

	if info.StartTime != "" && info.EndTime != "" {
		db = db.Where("created_at >= ? AND created_at <= ?", info.StartTime, info.EndTime)
	}

	if len(keyword) > 0 {
		db = db.Where("name LIKE ?", "%"+keyword+"%")
	}
	// tag为dir的数据置顶展示
	db = db.Order("CASE WHEN tag = 'dir' THEN 0 ELSE 1 END")
	err = db.Count(&total).Error
	if err != nil {
		return
	}
	err = db.Limit(limit).Offset(offset).Order("created_at desc").Find(&fileLists).Error
	return fileLists, total, err
}

//@author: [piexlmax](https://github.com/piexlmax)
//@function: GetFileRecordInfoList
//@description: 分页获取数据
//@param: info request.PageInfo
//@return: list interface{}, total int64, err error

func (e *FileUploadAndDownloadService) GetDirRecordInfoList(info request.PageInfo) (list interface{}, total int64, err error) {
	log.Printf("GetDirRecordInfoList 入参:%#v\n", info)

	limit := info.PageSize
	offset := info.PageSize * (info.Page - 1)
	keyword := info.Keyword

	db := global.GVA_DB.Model(&example.ExaFileUploadAndDownload{})
	var fileLists []example.ExaFileUploadAndDownload

	db = db.Where("tag != 'dir'")

	// 管理员可以看到所有的
	if info.UserName != "admin" {
		db = db.Where("(permission = ?) OR (permission = ? AND creator = ?)", true, false, info.UserName)
	}
	if info.GlobalSearch {
		wildcardSuffix := "%"
		if info.Dir != "/" {
			wildcardSuffix = "/" + wildcardSuffix
		}
		// 全局搜索：查询当前文件夹及其所有子文件夹
		db = db.Where("logic_address = ? OR logic_address LIKE ?", info.Dir, info.Dir+wildcardSuffix)
	} else {
		db = db.Where("logic_address = ?", info.Dir)
	}
	if info.Creator != "" {
		db = db.Where("creator LIKE ?", "%"+info.Creator+"%")
	}

	if info.StartTime != "" && info.EndTime != "" {
		db = db.Where("created_at >= ? AND created_at <= ?", info.StartTime, info.EndTime)
	}
	if len(keyword) > 0 {
		db = db.Where("name LIKE ?", "%"+keyword+"%")
	}
	err = db.Count(&total).Error
	if err != nil {
		return
	}
	err = db.Limit(limit).Offset(offset).Order("created_at desc").Find(&fileLists).Error
	return fileLists, total, err
}

// GetBackUpRecordInfoList
// @author: hanyuxin
// @description: 获取备份文件List
// @param: param
// @return: error
func (e *FileUploadAndDownloadService) GetBackUpRecordInfoList(info request.PageInfo) (list interface{}, total int64, err error) {
	log.Printf("GetBackUpRecordInfoList 入参:%#v\n", info)
	limit := info.PageSize
	offset := info.PageSize * (info.Page - 1)
	keyword := info.Keyword

	db := global.GVA_DB.Model(&example.ExaFileBackup{})
	var fileLists []example.ExaFileBackup
	//// 文件
	//if info.Tag != "" {
	//	if info.Tag == "txt" {
	//		db = db.Where("name LIKE ?", "%.txt")
	//	} else if info.Tag == "tp" {
	//		db = db.Where("(name LIKE ? OR name LIKE ? OR name LIKE ? OR name LIKE ? OR name LIKE ? OR name LIKE ?)",
	//			"%.bmp", "%.jpg", "%.png", "%.tif", "%.svg", "%.jpeg")
	//	} else if info.Tag == "xls" {
	//		db = db.Where("(name LIKE ? OR name LIKE ?)", "%.xls", "%.xlsx")
	//	} else if info.Tag == "wd" {
	//		db = db.Where("(name LIKE ? OR name LIKE ?)", "%.doc", "%.docx")
	//	} else if info.Tag == "ppt" {
	//		db = db.Where("(name LIKE ? OR name LIKE ?)", "%.ppt", "%.pptx")
	//	} else if info.Tag == "pdf" {
	//		db = db.Where("name LIKE ?", "%.pdf")
	//	} else if info.Tag == "zip" {
	//		db = db.Where("(name LIKE ? OR name LIKE ? OR name LIKE ?)", "%.rar", "%.zip", "%.7z")
	//	} else if info.Tag == "exe" {
	//		db = db.Where("name LIKE ?", "%.exe")
	//	} else if info.Tag == "else" {
	//		db = db.Where("name NOT LIKE ?", "%.txt")
	//		db = db.Where("name NOT LIKE ?", "%.bmp")
	//		db = db.Where("name NOT LIKE ?", "%.jpg")
	//		db = db.Where("name NOT LIKE ?", "%.png")
	//		db = db.Where("name NOT LIKE ?", "%.tif")
	//		db = db.Where("name NOT LIKE ?", "%.svg")
	//		db = db.Where("name NOT LIKE ?", "%.doc")
	//		db = db.Where("name NOT LIKE ?", "%.docx")
	//		db = db.Where("name NOT LIKE ?", "%.ppt")
	//		db = db.Where("name NOT LIKE ?", "%.pptx")
	//		db = db.Where("name NOT LIKE ?", "%.pdf")
	//		db = db.Where("name NOT LIKE ?", "%.rar")
	//		db = db.Where("name NOT LIKE ?", "%.zip")
	//		db = db.Where("name NOT LIKE ?", "%.7z")
	//		db = db.Where("name NOT LIKE ?", "%.exe")
	//		db = db.Where("name NOT LIKE ?", "%.xls")
	//		db = db.Where("name NOT LIKE ?", "%.xlsx")
	//	}
	//}
	if info.StartTime != "" && info.EndTime != "" {
		db = db.Where("created_at >= ? AND created_at <= ?", info.StartTime, info.EndTime)
	}
	if len(keyword) > 0 {
		db = db.Where("name LIKE ?", "%"+keyword+"%")
	}
	err = db.Count(&total).Error
	fmt.Println(total)
	if err != nil {
		return
	}
	err = db.Limit(limit).Offset(offset).Order("created_at desc").Find(&fileLists).Error
	return fileLists, total, err
}

//@author: [piexlmax](https://github.com/piexlmax)
//@function: UploadFile
//@description: 根据配置文件判断是文件上传到本地或者七牛云
//@param: header *multipart.FileHeader, noSave string
//@return: file model.ExaFileUploadAndDownload, err error

func (e *FileUploadAndDownloadService) UploadFile(header *multipart.FileHeader, param example.ExaUploadFile, f multipart.File) (file example.ExaFileUploadAndDownload, err error) {
	oss := upload.NewOss()
	// 上传文件到文件系统
	filePath, key, uploadErr := oss.UploadFile(header, param.UserName, f)
	if uploadErr != nil {
		panic(err)
	}
	fmt.Println("service")
	var filesize string
	if param.FileSize != "" {
		filesize = param.FileSize
	} else {
		filesize = strconv.FormatInt(header.Size, 10)
	}
	if param.NoSave == "0" {
		s := strings.Split(header.Filename, ".")
		f := example.ExaFileUploadAndDownload{
			Url:          filePath,
			Name:         header.Filename,
			Tag:          s[len(s)-1],
			Key:          key,
			Permission:   param.Permission,
			Creator:      param.UserName,
			LogicAddress: param.Dir,
			FileSize:     filesize,
		}
		// 更改数据库，记录上传记录
		return f, e.Upload(f)
	}
	return
}

// ChangePermission
// @author: chenbangjie3
// @description: 更改权限名
func (e *FileUploadAndDownloadService) ChangePermission(file example.ExaFileUploadAndDownload) error {
	var fileFromDb example.ExaFileUploadAndDownload
	return global.GVA_DB.Where("id = ?", file.ID).First(&fileFromDb).Update("permission", file.Permission).Error
}

// NewFolder
// @author: chenbangjie
// @description: 新建文件夹
// @param: dirName fileName string
// @return: error
func (e *FileUploadAndDownloadService) NewFolder(folder example.ExaNewFolder) error {
	f := example.ExaFileUploadAndDownload{
		Url:          "dir",
		Name:         folder.Name,
		Tag:          "dir",
		Key:          "dir",
		Permission:   folder.Permission, // 新建文件夹默认为私有
		Creator:      folder.UserName,
		LogicAddress: folder.DirName,
	}
	// 更改数据库，记录上传记录
	return e.Upload(f)
}

// GetDirList
// @author: chenbangjie
// @description: 获取文件夹List
// @param: param
// @return: error
func (e *FileUploadAndDownloadService) GetDirList(param example.ExaGetDirList) (interface{}, error) {
	var dirList []string
	err := global.GVA_DB.Model(&example.ExaFileUploadAndDownload{}).
		Select("name").
		Where("logic_address = ?", param.DirName).
		Where("tag = 'dir'").
		Pluck("name", &dirList).
		Error
	return dirList, err
}

// GetAllFileByDir
// @author: chenbangjie
// @description: 获取文件夹下的所有文件
// @param: param
// @return: error
func (e *FileUploadAndDownloadService) GetAllFileByDir(dir string, userName string) (interface{}, error) {
	var results []struct {
		URL  string `json:"url" gorm:"comment:文件地址"`
		Name string `json:"name" gorm:"comment:文件名"`
		Tag  string `json:"tag" gorm:"comment:文件标签"`
	}
	if userName == "admin" {
		err := global.GVA_DB.Model(&example.ExaFileUploadAndDownload{}).
			Select("url", "name", "tag").
			Where("logic_address = ? OR logic_address LIKE ?", dir, dir+"/%").
			Where("tag != 'dir'").
			Find(&results).
			Error
		return results, err
	} else {
		err := global.GVA_DB.Model(&example.ExaFileUploadAndDownload{}).
			Select("url", "name", "tag").
			Where("logic_address = ? OR logic_address LIKE ?", dir, dir+"/%").
			Where("tag != 'dir'").
			Where("(creator = ? and permission = ?) or permission = ?", userName, false, true).
			Find(&results).
			Error
		return results, err
	}

}

// GetBackupFileCount
// @author: hanyuxin
// @description: 获取备份文件数量
// @param:
// @return: error
func (e *FileUploadAndDownloadService) GetBackupFileCount(name string) (int64, error) {
	var count int64
	err := global.GVA_DB.Model(&example.ExaFileBackup{}).
		Where("name LIKE ?", name+"%").
		Count(&count).Error
	return count, err

}
